/*
 * LogEx a Java library for extracting log file data
 * Copyright 2012 LogEx Team.
 *
 * This program is free software. You can distribute or modify it under the 
 * terms of the GNU Lesser General Public License version 3.0 as published by  
 * the Free Software Foundation.
 *
 * This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
 * INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, contact the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
package org.logex.main;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xquery.XQException;

import org.basex.api.DatabaseHandler;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class XmlParser {
	public File xmlfile;
	private String inputFile = null;
	private String xmlDbFile = null;
	private DatabaseHandler databaseHandler;
	private ArrayList<String> documentList;
	private File file;
	private FileWriter fwstream;
	private BufferedWriter out;

	/**
	 * Constructor for <code>XmlParser</code> class.
	 * 
	 * @param fileName
	 *            Name of the log file
	 */
	public XmlParser(String fileName) {
		inputFile = fileName;
		if (inputFile.contains(File.separator)) {
			xmlDbFile = inputFile.substring(inputFile
					.lastIndexOf(File.separator) + 1);
		} else {
			xmlDbFile = inputFile;

		}
		documentList = new ArrayList<String>();
	}

	/**
	 * Convert XML DOM object to a string
	 * 
	 * @param doc
	 *            The document object created from the XML file
	 * 
	 * @throws TransformerConfigurationException
	 *             Indicates a serious configuration error
	 * @throws TransformerException
	 *             occurs due to an error in the transformation process
	 * 
	 * @return XML formated string to the buildDOM method
	 * 
	 */
	private String stringConverter(Document doc)
			throws TransformerConfigurationException, TransformerException {
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer transformer = tf.newTransformer();
		transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
		StringWriter writer = new StringWriter();
		transformer.transform(new DOMSource(doc), new StreamResult(writer));
		String output = writer.getBuffer().toString().replaceAll("\r", "");
		return output;

	}

	/**
	 * Creates a DOM object from a XML file
	 * 
	 * @return XML formated string to the DatabaseHandler class
	 * 
	 * @throws ParserConfigurationException
	 *             If a XML parser configuration error occurs
	 * @throws IOException
	 *             Due to errors in XML reading
	 * @throws SAXException
	 *             If a general SAX error or warning occurs
	 * @throws TransformerException
	 *             If XML transformation error occurs
	 * @throws TransformerConfigurationException
	 *             Indicates a serious configuration error
	 * 
	 */
	public String buildDOM() throws ParserConfigurationException, SAXException,
			IOException, TransformerConfigurationException,
			TransformerException {
		String xmlString = null;

		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
		Document doc = dBuilder.parse(inputFile);
		doc.getDocumentElement().normalize();
		xmlString = stringConverter(doc);
		return xmlString;
	}

	/**
	 * Writes the outermost elements of the XML document.
	 * 
	 * @param docName
	 *            Name of the XML document
	 * @throws IOException
	 *             Due to errors in writing to file
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 * @throws TransformerException
	 *             If XML transformation error occurs
	 * @throws SAXException
	 *             If a general SAX error or warning occurs
	 * @throws ParserConfigurationException
	 *             If a XML parser configuration error occurs
	 * @throws TransformerConfigurationException
	 *             If specifies an exceptional condition that occur during the
	 *             transformation process.
	 */
	private void updateDatabase(String docName) throws IOException,
			XQException, TransformerConfigurationException,
			ParserConfigurationException, SAXException, TransformerException {
		if (!checkDocumentExistence(docName)) {
			file = new File(System.getProperty(StringConstants.USER_DIR) + File.separator
					+ docName);
			file.createNewFile();
			fwstream = new FileWriter(System.getProperty(StringConstants.USER_DIR)
					+ File.separator + docName);
			out = new BufferedWriter(fwstream);
			out.write(StringConstants.LOG_FILE_START_TAG + "\n"
					+ StringConstants.NOTICE_START_TAG
					+ StringConstants.LOGEX_TEAM_MSG
					+ StringConstants.NOTICE_END_TAG + "\n"
					+ StringConstants.LOG_FILE_END_TAG);
			out.close();
			databaseHandler.addFile(docName);
		}
		databaseHandler.updateFile(docName, buildDOM());
	}

	/**
	 * Checks if a document exists under the current name.
	 * 
	 * @param docName
	 *            Name of the XML document
	 * @return Boolean value of the existence of the file
	 * 
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 * @throws IOException
	 *             Due to errors in database reading
	 * @throws FileNotFoundException
	 *             Occurs if the file denoted by a specified pathname has failed
	 */
	private boolean checkDocumentExistence(String docName) throws XQException,
			FileNotFoundException, IOException {
		String trimmedDoc;
		databaseHandler = new DatabaseHandler();
		documentList = databaseHandler.getDocumentNames();
		for (String document : documentList) {
			trimmedDoc = document.substring(document.lastIndexOf("/") + 1,
					document.length());

			if (docName.equals(trimmedDoc)) {
				return true;
			}
		}
		return false;
	}

	public static void main(String args[]) throws XQException,
			FileNotFoundException, IOException,
			TransformerConfigurationException, ParserConfigurationException,
			SAXException, TransformerException {
		XmlParser xp = new XmlParser(
				"C:\\Users\\Chathunga\\Desktop\\winscplog.xml");
		xp.updateDatabase(xp.xmlDbFile);

	}

	/**
	 * Get XML file name and location for DOM process.
	 * 
	 * @throws TransformerException
	 *             If XML transformation error occurs
	 * @throws SAXException
	 *             If a general SAX error or warning occurs
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 * @throws IOException
	 *             Due to errors in database reading
	 * @throws FileNotFoundException
	 *             Occurs if the file denoted by a specified pathname has failed
	 * @throws ParserConfigurationException
	 *             If a XML parser configuration error occurs
	 * @throws TransformerConfigurationException
	 *             If specifies an exceptional condition that occur during the
	 *             transformation process.
	 */
	public void getXmlFile() throws TransformerConfigurationException,
			IOException, XQException, ParserConfigurationException,
			SAXException, TransformerException {
		updateDatabase(xmlDbFile);
	}

}
